﻿#include "dxstdafx.h"

extern RGBQUAD* g_pColorTable;

void CommonFunc::ErrorMessageBox(LPCWSTR ErrorMessage)
{
	assert(0);
	::MessageBox(NULL, ErrorMessage, TEXT("ERROR"), MB_ICONERROR);
}

void CommonFunc::CheckFxWarning(LPD3DXBUFFER pCode)
{
	if (pCode)
	{
		LPVOID pBufErr = pCode->GetBufferPointer();
		char* ErrInfo = (char*)pBufErr;
		std::wstring strFxWarning = CommonFunc::StringToWString(ErrInfo);
		CommonFunc::ErrorMessageBox(strFxWarning.c_str());
		pCode->Release();
	}
}

bool CommonFunc::Write8BitBmp(const std::wstring &wpath, const BYTE* pBmpBuf, RGBQUAD* pColorTable, int imWidth, int imHeight)
{
	FILE *fid = NULL;
	_wfopen_s(&fid, wpath.c_str(), L"wb");
	CHECK_RE_FALSE(fid)

	int colorTablesize = 1024;
	if (imWidth % 4 != 0)
	{
		CString strError;
		strError.Format(L"%s Width isn't Multiple of 4!", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	
	BITMAPFILEHEADER fileHead;
	fileHead.bfType = 0x4D42;	//bmp类型
	fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + imWidth * imHeight;	//bfSize是图像文件4个组成部分之和
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;
	fileHead.bfOffBits = 54 + colorTablesize;	//bfOffBits是图像文件前3个部分所需空间之和
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fid);	//写文件头进文件

	BITMAPINFOHEADER head;	//申请位图信息头结构变量，填写信息头信息
	head.biBitCount = 8;
	head.biClrImportant = 0;
	head.biClrUsed = 0;
	head.biCompression = 0;
	head.biHeight = imHeight;
	head.biPlanes = 1;
	head.biSize = 40;
	head.biSizeImage = imWidth * imHeight;
	head.biWidth = imWidth;
	head.biXPelsPerMeter = 0;
	head.biYPelsPerMeter = 0;
	fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fid);	//写位图信息头进内存

	DWORD dwWriteCount = (DWORD)fwrite(pColorTable, sizeof(RGBQUAD), 256, fid);
	if (0 <= dwWriteCount && dwWriteCount < 256) // 补足
	{
		RGBQUAD* pColorTableFull = Get8BitColorTable();
		fwrite(pColorTableFull, sizeof(RGBQUAD), 256 - dwWriteCount, fid);
	}
	else if (dwWriteCount != 256)
	{
		fclose(fid);
		CString strError;
		strError.Format(L"ColorTable Error when Write 8Bit Bmp:%s", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	
	fwrite(pBmpBuf, sizeof(BYTE), imWidth * imHeight, fid);
	
	fclose(fid);
	return true;
}

bool CommonFunc::Read8BitBmpWithBYTE(const std::wstring &wpath, BYTE* &pBmpBuf, int* imWidth, int* imHeight)
{
	FILE *fid = NULL;
	_wfopen_s(&fid, wpath.c_str(), L"rb+");
	CHECK_RE_FALSE(fid);

	fseek(fid, sizeof(BITMAPFILEHEADER), SEEK_CUR);		//跳过位图文件头
	//定义位图信息头结构变量，读取位图信息头进内存，存放在变量head中
	BITMAPINFOHEADER head;
	fread(&head, sizeof(BITMAPINFOHEADER), 1, fid);		//获取图像宽、高、每像素所占位数等信息
	*imWidth = head.biWidth;
	*imHeight = head.biHeight;
	int nColorCount = (head.biClrUsed == 0) ? 256 : head.biClrUsed;
	int biBitCount = head.biBitCount;
	if (biBitCount == 8)	 //灰度图像有颜色表，且颜色表表项为nColorCount
	{
		fseek(fid, nColorCount * sizeof(RGBQUAD), SEEK_CUR);
	}
	else
	{
		fclose(fid);
		CString strError;
		strError.Format(L"%s isn't 8bit", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	*imWidth = (*imWidth * biBitCount / 8 + 3) / 4 * 4;		//定义变量，计算图像每行像素所占的字节数（必须是4的倍数）

	//申请空间
	DWORD length = (*imWidth) * (*imHeight);
	pBmpBuf = new BYTE[length];
	if (!fread(pBmpBuf, sizeof(BYTE), length, fid))
	{
		fclose(fid);
		CString strError;
		strError.Format(L"fread %s failure!", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	fclose(fid);
	return true;
}

/*bool CommonFunc::Read8BitBmpWithColor(const std::wstring &wpath, _StructRGB** &pRGBBuf, int* imWidth, int* imHeight)
{
	FILE *fid = NULL;
	//打开高度图
	_wfopen_s(&fid, wpath.c_str(), L"rb+");
	if (NULL == fid)
	{
		return false;
	}
	//跳过位图文件头结构BITMAPFILEHEADER
	fseek(fid, sizeof(BITMAPFILEHEADER), SEEK_CUR);
	//定义位图信息头结构变量，读取位图信息头进内存，存放在变量head中
	BITMAPINFOHEADER head;
	fread(&head, sizeof(BITMAPINFOHEADER), 1, fid); //获取图像宽、高、每像素所占位数等信息
	*imWidth = head.biWidth;
	*imHeight = head.biHeight;
	int biBitCount = head.biBitCount;
	int nColorCount = head.biClrUsed == 0 ? 256 : head.biClrUsed;
	RGBQUAD* pColorTable = NULL;
	if (biBitCount == 8) //灰度图像有颜色表，且颜色表表项为nColorCount
	{
		//申请颜色表所需要的空间，读颜色表进内存
		pColorTable = new RGBQUAD[nColorCount];
		fread(pColorTable, sizeof(RGBQUAD), nColorCount, fid);
	}
	else
	{
		fclose(fid);
		CString strError;
		strError.Format(L"%s isn't 8bit", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	*imWidth = (*imWidth * biBitCount / 8 + 3) / 4 * 4; //定义变量，计算图像每行像素所占的字节数（必须是4的倍数）

	//申请二维数组的空间
	pRGBBuf = new _StructRGB*[*imHeight];
	for (int i = 0; i < *imHeight; ++i)
	{
		pRGBBuf[i] = new _StructRGB[*imWidth];
	}

	for (int a = 0; a < *imHeight; ++a)
	{
		for (int b = 0; b < *imWidth; ++b)
		{
			BYTE temp;
			if (!fread(&temp, sizeof(char), 1, fid) || temp >= nColorCount)
			{
				fclose(fid);
				CString strError;
				strError.Format(L"fread %s failure!", wpath.c_str());
				ErrorMessageBox(strError);
				return false;
			}
			pRGBBuf[a][b].red = pColorTable[temp].rgbRed;
			pRGBBuf[a][b].green = pColorTable[temp].rgbGreen;
			pRGBBuf[a][b].blue = pColorTable[temp].rgbBlue;
		}
	}
	fclose(fid);
	delete[] pColorTable;
	return true;
}
*/

bool CommonFunc::Read24BitBmp(const std::wstring &wpath, _stRGB* &pRGBBuf, int* imWidth, int* imHeight)
{
	FILE *fid = NULL;
	_wfopen_s(&fid, wpath.c_str(), L"rb");	//二进制读方式打开指定的图像文件
	CHECK_RE_FALSE(fid);

	//跳过位图文件头结构BITMAPFILEHEADER
	fseek(fid, sizeof(BITMAPFILEHEADER), SEEK_CUR);
	//定义位图信息头结构变量，读取位图信息头进内存，存放在变量head中
	BITMAPINFOHEADER head;
	fread(&head, sizeof(BITMAPINFOHEADER), 1, fid);		//获取图像宽、高、每像素所占位数等信息
	*imWidth = head.biWidth;
	*imHeight = head.biHeight;
	int biBitCount = head.biBitCount;
	if (biBitCount != 24)
	{
		fclose(fid);	//关闭文件
		CString strError("Normal Map isn't 24bit");
		ErrorMessageBox(strError);
		return false;
	}
	*imWidth = (*imWidth * biBitCount / 24 + 3) / 4 * 4;	//定义变量，计算图像每行像素所占的字节数（必须是4的倍数）
	//申请位图数据所需要的空间，读位图数据进内存
	DWORD length = (*imWidth) * (*imHeight);
	pRGBBuf = new _stRGB[length];

	if (!fread(pRGBBuf, sizeof(_stRGB), length, fid))
	{
		fclose(fid);
		CString strError;
		strError.Format(L"fread %s failure!", wpath.c_str());
		ErrorMessageBox(strError);
		return false;
	}
	fclose(fid);	//关闭文件
	return true;	//读取文件成功
}

std::wstring CommonFunc::ReadInputFile(const std::wstring &wpath)
{
	std::wifstream wif(wpath);
	wif.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
	std::wstringstream wss;
	wss << wif.rdbuf();
	return wss.str();
}

void CommonFunc::RelativePath2FullPath(const std::wstring &wpath, std::wstring &wpathOut)
{
	TCHAR szAppPath[MAX_PATH];
	TCHAR szRcPath[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, szAppPath);
	wcscpy_s(szRcPath, szAppPath);
	wcscat_s(szRcPath, L"\\..");
	wcscat_s(szRcPath, wpath.c_str());
	wpathOut = szRcPath;
}

std::wstring CommonFunc::StringToWString(const std::string &strIn)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t> > myconv;
	return myconv.from_bytes(strIn);
}

std::string CommonFunc::WStringToString(const std::wstring &wstrIn)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t> > myconv;
	return myconv.to_bytes(wstrIn);
}

void CommonFunc::GetScreenWidthnHeight(int* nWidth, int* nHeight)
{
	DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
	if (deviceSettings.ver == DXUT_D3D9_DEVICE)
	{
		*nWidth = deviceSettings.d3d9.pp.BackBufferWidth;
		*nHeight = deviceSettings.d3d9.pp.BackBufferHeight;
	}
	else
	{
		*nWidth = deviceSettings.d3d10.sd.BufferDesc.Width;
		*nHeight = deviceSettings.d3d10.sd.BufferDesc.Height;
	}
}

void CommonFunc::GetMyPersonalLocation(std::wstring& wstrOut)
{
	TCHAR m_lpszDefaultDir[MAX_PATH];
	TCHAR szDocument[MAX_PATH] = { 0 };
	memset(m_lpszDefaultDir, 0, _MAX_PATH);

	LPITEMIDLIST pidl = NULL;
	SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
	if (pidl && SHGetPathFromIDList(pidl, szDocument))
	{
		GetShortPathName(szDocument, m_lpszDefaultDir, _MAX_PATH);
	}
	lstrcat(m_lpszDefaultDir, L"\\EmptyProject");
	wstrOut = m_lpszDefaultDir;
}

RGBQUAD* CommonFunc::Get8BitColorTable()
{
	if (NULL == g_pColorTable)
	{
		g_pColorTable = new RGBQUAD[256];
		for (int i = 0; i < 256; ++i)
		{
			g_pColorTable[i].rgbBlue = g_pColorTable[i].rgbGreen = g_pColorTable[i].rgbRed = i;
			g_pColorTable[i].rgbReserved = 0;
		}
		return g_pColorTable;
	}
	else
	{
		return g_pColorTable;
	}
}

void CommonFunc::GetPersonalPathCacheDirectory( std::wstring &wPathOut )
{
	GetMyPersonalLocation(wPathOut);
	CreateDirectory(wPathOut.c_str(), NULL);
	wPathOut.append(L"\\cache");
	CreateDirectory(wPathOut.c_str(), NULL);
	SetFileAttributes(wPathOut.c_str(), FILE_ATTRIBUTE_HIDDEN);
}

D3DXVECTOR2 CommonFunc::Cursor2CameraSpace(const CPoint& ptCursor)
{
	// 鼠标是左上角为(0, 0) 摄像机空间为左下角为(-1, -1)
	int nScreenWidth = 0, nScreenHeight = 0;
	GetScreenWidthnHeight(&nScreenWidth, &nScreenHeight);
	D3DXVECTOR2 ptOut;
	ptOut.x = (ptCursor.x - nScreenWidth / 2.f) * 2.f / nScreenWidth;
	ptOut.y = (nScreenHeight / 2.f - ptCursor.y) * 2.f / nScreenHeight;
	return ptOut;
}

void CommonFunc::SubJsonAnnotation(std::wstring& wstrInOut)
{
	try
	{
		static const std::wregex pattern(L"(#.*)");
		wstrInOut = std::regex_replace(wstrInOut, pattern, L"$2");
	}
	catch (std::regex_error e)
	{
		CString strError;
		strError.Format(L"%s\ncode:%d", e.what(), e.code());
		CommonFunc::ErrorMessageBox(strError);
	}
}

void CommonFunc::GetFolderFile(const std::wstring& FolderPath, const std::wstring& DocumentFormat, std::list<std::wstring>& FileNameList)
{
	_wfinddata_t fileinfo;
	std::wstring dir = FolderPath + L"*." + DocumentFormat;
	intptr_t hFile = 0;
//	std::wstring p;

	if ((hFile = _wfindfirst(dir.c_str(), &fileinfo)) != -1)
	{
		do
		{
			//如果是目录,不用管
			//如果不是,加入列表
			if ((fileinfo.attrib &  _A_SUBDIR))
			{
				continue;
// 				if (wcscmp(fileinfo.name, L".") != 0 && wcscmp(fileinfo.name, L"..") != 0)
// 					GetFolderFile(p.assign(FolderPath).append(fileinfo.name).append(L"\\"), DocumentFormat, FileNameArray);
			}
			else
			{
				std::wstring fileinfoname = fileinfo.name;		// 包含后缀
				size_t findpos = fileinfoname.rfind(L"." + DocumentFormat);
				if (std::wstring::npos == findpos)
				{
					CommonFunc::ErrorMessageBox(L"Function 'GetFolderFile' Error!");
				}
				else
				{
					FileNameList.push_back(fileinfoname.substr(0, findpos));
				}
			}
		} while (_wfindnext(hFile, &fileinfo) == 0);
		_findclose(hFile);
	}
}

long long CMathFunc::XYTran2Index(long long x, long long y, long long width, long long height)
{
	x = Saturate<long long>(x, 0, width - 1);
	y = Saturate<long long>(y, 0, height - 1);
	return y * width + x;
}

void CMathFunc::IndexTran2XY(int* x, int* y, int index, int width, int height)
{
	*x = Saturate(index % width, 0, width - 1);
	*y = Saturate(index / width, 0, height - 1);
}

D3DXVECTOR2 CMathFunc::Vec2Rotate(const D3DXVECTOR2& vec2, double ang)
{
	D3DXVECTOR2 ans;
	double cosa = cos(ang);
	double sina = sin(ang);
	ans.x = cosa * vec2.x + sina * vec2.y;
	ans.y = cosa * vec2.y - sina * vec2.x;
	return ans;
}
